/// @tags: NetworkFlow
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <map>
#include <queue>
#include <vector>

using namespace std;

namespace BlueQuantum {

int const N = 2e4 + 5, M = 1e4 + 5, INF = 0x3f3f3f3f;

int n, m;
map<pair<int, int>, int> mp;

struct Edge {
  int v, nxt, f;
};

namespace TreeChainPartition {
int idfn[N], id[N];
}

namespace NetworkFlow {

int s, t, e_cnt = 1;
int heads[N * 4 + M], cur[N * 4 + M], cvt[N * 4 + M], dep[N * 4 + M];
bool vis[N * 4 + M];
Edge e[(N * 6 + M + M * 15 * 15) * 2];

inline void add(int u, int v, int f) {
  e[++e_cnt].v = v, e[e_cnt].nxt = heads[u], heads[u] = e_cnt, e[e_cnt].f = f;
  e[++e_cnt].v = u, e[e_cnt].nxt = heads[v], heads[v] = e_cnt, e[e_cnt].f = 0;
}

inline bool bfs() {
  memset(dep, 0, sizeof(dep));
  memcpy(cur, heads, sizeof(cur));
  queue<int> q;
  dep[s] = 1;
  q.push(s);
  while (!q.empty()) {
    int u = q.front();
    q.pop();
    for (int i = heads[u], v; i; i = e[i].nxt) {
      if (dep[v = e[i].v] == 0 && e[i].f) {
        dep[v] = dep[u] + 1;
        q.push(v);
      }
    }
  }
  return dep[t] != 0;
}

int dinic(int u, int flow) {
  if (u == t) return flow;
  int rest = flow;
  for (int &i = cur[u], v; i; i = e[i].nxt) {
    if (dep[v = e[i].v] == dep[u] + 1 && e[i].f) {
      int k = dinic(v, min(rest, e[i].f));
      if (k == 0) dep[v] = 0;
      e[i].f -= k, e[i ^ 1].f += k;
      rest -= k;
      if (rest == 0) break;
    }
  }
  if (rest == 0) dep[u] = 0;
  return flow - rest;
}

inline int getMaxFlow() {
  int res = 0;
  while (bfs()) res += dinic(s, INF);
  return res;
}

void dfs(int u) {
  vis[u] = true;
  for (int i = heads[u]; i; i = e[i].nxt)
    if (e[i].f && vis[e[i].v] == false) dfs(e[i].v);
}

inline void output() {
  dfs(s);
  vector<int> people, edge;
  for (int i = heads[s]; i; i = e[i].nxt)
    if (vis[e[i].v] == false) people.push_back(e[i].v - 4 * n);
  for (int i = heads[t]; i; i = e[i].nxt)
    if (vis[e[i].v] == true)
      edge.push_back(TreeChainPartition::id[TreeChainPartition::idfn[cvt[e[i].v]]]);
  cout << people.size() << ' ';
  for (vector<int>::iterator i = people.begin(), ilim = people.end(); i != ilim; ++i)
    cout << *i << ' ';
  cout << '\n';
  cout << edge.size() << ' ';
  for (vector<int>::iterator i = edge.begin(), ilim = edge.end(); i != ilim; ++i)
    cout << *i << ' ';
}

}  // namespace NetworkFlow
using NetworkFlow::s;
using NetworkFlow::t;

namespace TreeChainPartition {

int e_cnt, d_cnt;
int dep[N], fa[N], siz[N], son[N], top[N], dfn[N], heads[N];
Edge e[N * 2];

inline void add(int u, int v) {
  e[++e_cnt].v = v, e[e_cnt].nxt = heads[u], heads[u] = e_cnt;
}

void dfs1(int u) {
  siz[u] = 1, id[u] = mp[make_pair(u, fa[u])];
  for (int i = heads[u], v; i; i = e[i].nxt)
    if ((v = e[i].v) != fa[u]) {
      fa[v] = u, dep[v] = dep[u] + 1;
      dfs1(v);
      siz[u] += siz[v];
      if (siz[v] > siz[son[u]]) son[u] = v;
    }
}

void dfs2(int u, int t) {
  top[u] = t, dfn[u] = ++d_cnt, idfn[d_cnt] = u;
  if (son[u]) dfs2(son[u], t);
  for (int i = heads[u], v; i; i = e[i].nxt)
    if ((v = e[i].v) != fa[u] && v != son[u]) dfs2(v, v);
}

inline void prework() { fa[1] = 1, dfs1(1), dfs2(1, 1); }

void build(int x, int l, int r, int node) {
  if (l == r) return NetworkFlow::cvt[x] = l, NetworkFlow::add(x, node, 1);
  int mid = (l + r) >> 1, ls = x << 1, rs = x << 1 | 1;
  NetworkFlow::add(x, ls, INF), NetworkFlow::add(x, rs, INF);
  build(ls, l, mid, node);
  build(rs, mid + 1, r, node);
}

void modify(int x, int l, int r, int L, int R, int node) {
  if (L <= l && r <= R) return NetworkFlow::add(node, x, INF);
  int mid = (l + r) >> 1;
  if (L <= mid) modify(x << 1, l, mid, L, R, node);
  if (mid < R) modify(x << 1 | 1, mid + 1, r, L, R, node);
}

inline void modify(int u, int v, int x) {
  while (top[u] != top[v]) {
    if (dep[top[u]] < dep[top[v]]) swap(u, v);
    modify(1, 1, n, dfn[top[u]], dfn[u], x);
    u = fa[top[u]];
  }
  if (dfn[u] > dfn[v]) swap(u, v);
  if (u != v) modify(1, 1, n, dfn[u] + 1, dfn[v], x);
}

}  // namespace TreeChainPartition

inline int main() {
  cin >> n >> m;
  for (int i = 1, u, v; i < n; ++i) {
    cin >> u >> v;
    TreeChainPartition::add(u, v);
    TreeChainPartition::add(v, u);
    mp[make_pair(u, v)] = mp[make_pair(v, u)] = i;
  }
  s = 0, t = n * 4 + m + 1;
  TreeChainPartition::prework();
  TreeChainPartition::build(1, 1, n, t);
  for (int i = 1, l, r; i <= m; ++i) {
    cin >> l >> r;
    TreeChainPartition::modify(l, r, n * 4 + i), NetworkFlow::add(s, n * 4 + i, 1);
  }
  cout << NetworkFlow::getMaxFlow() << '\n';
  NetworkFlow::output();
  return 0;
}

}  // namespace BlueQuantum

int main() {
#ifndef ONLINE_JUDGE
#ifdef LOCAL
  freopen("/tmp/CodeTmp/testdata.in", "r", stdin);
  freopen("/tmp/CodeTmp/testdata.out", "w", stdout);
#else
  freopen("CF786E ALT.in", "r", stdin);
  freopen("CF786E ALT.out", "w", stdout);
#endif
#endif

  ios::sync_with_stdio(false), cin.tie(NULL), cout.tie(NULL);
  return BlueQuantum::main();
}
